#include "aes_crypt.h"

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include <errno.h>

#include <openssl/evp.h>
#include <openssl/rand.h>

#include "debug.h"

static unsigned char *iv = (unsigned char *)"0123456789012345";

static int _aes_encrypt(const unsigned char *plaintext,int palintext_len,const unsigned char *key,const unsigned char *iv,unsigned char *ciphertext);
static int _aes_decrypt(const unsigned char *ciphertext,int ciphertext_len,const unsigned char *key,const unsigned char *iv,unsigned char *plaintext);
static int _aes_generate_rand_key(unsigned char *buf,int len);

int _aes_encrypt(const unsigned char *plaintext,int palintext_len,const unsigned char *key,const unsigned char *iv,unsigned char *ciphertext)
{
    int ret = -1;
    EVP_CIPHER_CTX ctx;
    int ciphertext_len;
    int tmplen;

    EVP_CIPHER_CTX_init(&ctx);

    ret = EVP_EncryptInit_ex(&ctx,EVP_aes_256_cfb128(),NULL,key,iv);
    if(ret != 1)
    {
        PRINTF("EVP_EncryptInit_ex error..\r\n");
        return ret;
    }

    ret = EVP_EncryptUpdate(&ctx,ciphertext,&ciphertext_len,plaintext,palintext_len);
    if(ret != 1)
    {
        PRINTF("EVP_EncryptUpdate error..\r\n");
        return ret;
    }

    ret = EVP_EncryptFinal_ex(&ctx,ciphertext + ciphertext_len,&tmplen);
    if(ret != 1)
    {
        PRINTF("EVP_EncryptFinal_ex error..\r\n");
        return ret;
    }
    ciphertext_len += tmplen;

    EVP_CIPHER_CTX_cleanup(&ctx);

    ret = ciphertext_len;

    return ciphertext_len;
}

int _aes_decrypt(const unsigned char *ciphertext,int ciphertext_len,const unsigned char *key,const unsigned char *iv,unsigned char *plaintext)
{
    int ret = -1;
    EVP_CIPHER_CTX ctx;
    int plaintext_len;
    int tmplen;

    EVP_CIPHER_CTX_init(&ctx);

    ret = EVP_DecryptInit_ex(&ctx,EVP_aes_256_cfb128(),NULL,key,iv);
    if(ret != 1)
    {
        PRINTF("EVP_DecryptInit_ex error..\r\n");
        return ret;
    }

    ret = EVP_DecryptUpdate(&ctx,plaintext,&plaintext_len,ciphertext,ciphertext_len);
    if(ret != 1)
    {
        PRINTF("EVP_DecryptUpdate error..\r\n");
        return ret;
    }

    ret = EVP_DecryptFinal_ex(&ctx,plaintext + plaintext_len,&tmplen);
    if(ret != 1)
    {
        PRINTF("EVP_DecryptFinal_ex error..\r\n");
        return ret;
    }
    plaintext_len += tmplen;

    EVP_CIPHER_CTX_cleanup(&ctx);

    ret = plaintext_len;

    return ret;
}

int _aes_generate_rand_key(unsigned char *buf,int len)
{
    return RAND_bytes(buf,len);
}

int aes_encrypt(const unsigned char *plaintext,int palintext_len,const unsigned char *key,unsigned char *ciphertext)
{
    return _aes_encrypt(plaintext,palintext_len,key,iv,ciphertext);
}

int aes_decrypt(const unsigned char *ciphertext,int ciphertext_len,const unsigned char *key,unsigned char *plaintext)
{
    return _aes_decrypt(ciphertext,ciphertext_len,key,iv,plaintext);
}

int aes_generate_rand_key(unsigned char *buf)
{
    return _aes_generate_rand_key(buf,AES_KEY_LEN);
}
